#include "MainWindow.h"


MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
    this->_initWindow();
    this->_connectSlots();
    this->eventuallyRestoreAfterCrash();
    //TODO add _ajustFromSettings for volume for instance
}

void MainWindow::_initWindow(){
    setupUi(this);
    this->_initVariables();
    this->_initWindows();
    this->_initMlt();
    this->loadSettings();
}

void MainWindow::_initVariables(){
    this->isMaximized = false;
    this->hasBeenStopped = false;
    this->_initPlayPauseIcons();
    this->_initTimeLabel();
    this->_initSliderTimer();
    this->_ajustFromSettings();
}

void MainWindow::_initPlayPauseIcons(){
    this->playIcon = new QIcon();
    this->pauseIcon = new QIcon();
    this->playIcon->addFile(QString::fromUtf8(":/icons/icons/media-play.png"), QSize(), QIcon::Normal, QIcon::Off);
    this->pauseIcon->addFile(QString::fromUtf8(":/icons/icons/media-pause.png"), QSize(), QIcon::Normal, QIcon::Off);
}

void MainWindow::_initTimeLabel(){
    this->readingTimeLabel = new QLabel(TEXT_TIME, this);
    this->statusBar()->addPermanentWidget(this->readingTimeLabel);
}

void MainWindow::_initSliderTimer(){
    this->timer = new QTimer();
    this->connect(this->timer, SIGNAL(timeout()), this, SLOT(updateReadingSliderAndTime()));
}

void MainWindow::_initWindows(){
    this->editExtractionsWindow = new EditExtractionsWindow(this);
    this->optionsWindow = new OptionsWindow(this);
}

void MainWindow::_initMlt(){
    this->videoManager = VideoManagerSingleton::getInstance();
    this->videoManager->initMlt(this->getVideoWidgetId(), this->editExtractionsWindow->getVideoWidgetId());
}

void MainWindow::_ajustFromSettings(){
    this->volumeSlider->setValue(this->settings.getVolume());
}

void MainWindow::_connectSlots(){
    this->connect(this->closeAction, SIGNAL(triggered()), this, SLOT(close()));
    this->connect(this->editButton, SIGNAL(clicked()), this, SLOT(showEditExtractionsWindow()));
    this->connect(this->optionsAction, SIGNAL(triggered()), this->optionsWindow, SLOT(show()));
    this->connect(this->openAction, SIGNAL(triggered()), this, SLOT(openVideo()));
    this->connect(this->playAction, SIGNAL(triggered()), this, SLOT(playOrPause()));
    this->connect(this->playButton, SIGNAL(clicked()), this, SLOT(playOrPause()));
    this->connect(this->stopAction, SIGNAL(triggered()), this, SLOT(stop()));
    this->connect(this->stopButton, SIGNAL(clicked()), this, SLOT(stop()));
    this->connect(this->readingSlider, SIGNAL(sliderMoved(int)), this, SLOT(seek(int)));
    this->connect(this->volumeSlider, SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
    this->connect(this->extractAction, SIGNAL(triggered()), this, SLOT(addExtraction()));
    this->connect(this->extractButton, SIGNAL(clicked()), this, SLOT(addExtraction()));
    this->connect(this->videoWidget, SIGNAL(doubleClicked()), this, SLOT(showNormalOrMaximized()));
    this->connect(this, SIGNAL(play()), this->editExtractionsWindow, SLOT(setPlayIcon()));
    this->connect(this->editExtractionsWindow, SIGNAL(play()), this, SLOT(setPlayIcon()));
    this->connect(this, SIGNAL(play()), this, SLOT(setPauseIcon()));
    this->connect(this, SIGNAL(pause()), this, SLOT(setPlayIcon()));
    this->connect(this->editExtractionsWindow, SIGNAL(play()), this->editExtractionsWindow, SLOT(setPauseIcon()));
    this->connect(this->editExtractionsWindow, SIGNAL(pause()), this->editExtractionsWindow, SLOT(setPlayIcon()));
    this->connect(this->videoManager, SIGNAL(videoFinished()), this, SLOT(eventuallyReplayVideo()));
    this->connect(this->continueAction, SIGNAL(toggled(bool)), this->continueButton, SLOT(setChecked(bool)));
    this->connect(this->continueButton, SIGNAL(toggled(bool)), this->continueAction, SLOT(setChecked(bool)));
}

int MainWindow::getVideoWidgetId(){
        return (int)this->videoWidget->winId();
}

MainWindow::~MainWindow(){
    this->timer->stop();
    delete this->timer;
    delete VideoManagerSingleton::getInstance(); //TODO is it the best place to put that ?
    delete this->playIcon;
    delete this->pauseIcon;
}

void MainWindow::closeEvent(QCloseEvent* ce ){
    Q_UNUSED(ce);
    this->setCrashed(false);
}

void MainWindow::eventuallyRestoreAfterCrash(){
    if(this->hasCrashed()){
        int answer = QMessageBox::question(this, tr("L'application a planté"), tr("Voulez vous restaurer la session précédente ?"), QMessageBox::Yes | QMessageBox::No);
        if(answer == QMessageBox::Yes){
            this->restoreAfterCrash();
            this->updateAfterOpeningVideo();
            this->_pause();
        }
    }
}

void MainWindow::restoreAfterCrash(){
    this->videoManager->restoreAfterCrash();
    this->editExtractionsWindow->addAllExtractions();
}

void MainWindow::openVideo(){
    this->readingSlider->setValue(0);
    QString fileName = QFileDialog::getOpenFileName(this);
    this->openVideo(fileName);
}

void MainWindow::openVideo(QString fileName){
    if(!fileName.isNull()){
        this->videoManager->openVideo(fileName);
        this->lastOpenedFileName = fileName;
        this->updateAfterOpeningVideo();
    }
    //TODO what if the file is not valid or not a video file ?
    //TODO add _ajustFromSettings for volume for instance or video effect
}


void MainWindow::updateAfterOpeningVideo(){
    this->realReadingSliderValue = 0.0;
    this->videoManager->createRestoreFile();
    this->setPauseIcon();
    this->_updateBoundariesSlider();
    this->timer->start(200);
    this->setCrashed(true);
    this->_ajustVideoFromUserInterfaceChoice();
    this->readingSlider->setValue(0);
}


void MainWindow::eventuallyReplayVideo(){
    //this->seek(0);
    //this->readingSlider->setValue(this->readingSlider->maximum());
    this->stop();
    this->realReadingSliderValue = 0.0;
    if(this->settings.isContinuePlaying()){
        this->_play();
    }
}

void MainWindow::_ajustVideoFromUserInterfaceChoice(){
    this->setVolume(this->volumeSlider->value());
}

void MainWindow::setCrashed(bool crashed){
    this->settings.setCrashed(crashed);
}

bool MainWindow::hasCrashed(){
    return this->settings.hasCrashed();
}

void MainWindow::setPauseIcon(){
    this->playAction->setText(tr("&Pause"));
    this->playAction->setToolTip(tr("Pause"));
    this->playButton->setToolTip(tr("Pause"));
    this->playButton->setIcon(*this->pauseIcon);
}

void MainWindow::playOrPause(){
    if(this->videoManager->isPlayingMainVideo()){
        this->_pause();
    }else{
        this->_play();
    }
}

void MainWindow::_pause(){
    this->videoManager->pauseMainVideo();
    emit pause();
}

void MainWindow::setPlayIcon(){
    this->playAction->setText(tr("&Lire"));
    this->playAction->setToolTip(tr("Lire"));
    this->playButton->setToolTip(tr("Lire"));
    this->playButton->setIcon(*this->playIcon);
}

void MainWindow::_play(){
    if(!this->hasBeenStopped){
        this->videoManager->playMainVideo();
    }else{
        this->openVideo(this->lastOpenedFileName);
    }
    if(this->videoManager->isPlayingMainVideo()){
        emit play();
        this->hasBeenStopped = false;
        this->timer->start(200);
    }
}

void MainWindow::stop(){
    this->timer->stop();
    this->readingSlider->setValue(0);
    this->realReadingSliderValue = 0;
    this->setPlayIcon();
    this->videoManager->stopMainVideo();
    this->hasBeenStopped = true;
    this->readingTimeLabel->setText(TEXT_TIME); //TODO make a macro or something similar to avoid code repetition
}

void MainWindow::_updateBoundariesSlider(){
    this->readingSlider->setMaximum(this->videoManager->getNFrames());
}

void MainWindow::updateReadingSliderAndTime(){
    this->updateReadingSlider();
    this->updateTime();
}

void MainWindow::updateReadingSlider(){
    double fps = this->videoManager->getFps();
    int maximum = this->videoManager->getNFrames();
    if(!this->readingSlider->isSliderDown()  && this->videoManager->isPlayingMainVideo()){
        //int sliderValue = this->readingSlider->value();
        this->realReadingSliderValue +=  fps*REFRESH_SLIDER_TIME/1000.0;
        //int currentPosition = sliderValue + fps*REFRESH_SLIDER_TIME/1000.0;
        if(this->realReadingSliderValue <= maximum){
            this->readingSlider->setValue(this->realReadingSliderValue); //TODO understand why this go to the maximum and then come back...may be a wrong seek
        }else{
            this->readingSlider->setValue(maximum);
        }
    }
}

void MainWindow::updateTime(){
    int maxTimeInSec = this->videoManager->getMaxTimeMainVideo();
    QTime maxTime(0, 0, 0);
    maxTime = maxTime.addSecs(maxTimeInSec);
    int currentTimeInSec = this->videoManager->getCurrentTimeMainVideo();
    QTime currentTime(0, 0, 0);
    currentTime = currentTime.addSecs(currentTimeInSec);
    QString format("mm:ss");
    if(maxTimeInSec / 3600 > 0){
        format = QString("hh:") + format;
    }
    this->readingTimeLabel->setText(currentTime.toString(format) + "/" + maxTime.toString(format));
}

void MainWindow::seek(int position){
    if(!this->videoManager->isStopMainVideo()){
        this->realReadingSliderValue = position;
        this->videoManager->seekMainVideo(position);
    }
}

void MainWindow::setVolume(int position){
    //TODO find out how to attach a sound effect
    this->videoManager->setVolume(position);
}

void MainWindow::addExtraction(){
    int idMethod = this->settings.getIdExtractionMethod();
    if(idMethod == 0){
        int nMaxSecBefore = this->settings.getAutomaticMaxNSecBefore();
        int nMaxSecAfter = this->settings.getAutomaticMaxNSecAfter();
        double sensibility = this->settings.getAutomaticSensibility()/100.0;
        int medianDataSize = this->settings.getAutomaticMedianDataSize();
        this->videoManager->addExtractionWithAutomaticMethod(nMaxSecBefore, nMaxSecAfter, sensibility, medianDataSize);
    }else{
        int nSecBefore = this->settings.getNormalNSecBefore();
        int nSecAfter = this->settings.getNormalNSecAfter();
        this->videoManager->addExtractionWithSimpleMethod(nSecBefore, nSecAfter);
    }
}


void MainWindow::showEditExtractionsWindow(){
    this->_pause();
    if(this->videoManager->isCalculingExtraction()){
        this->editExtractionsWindow->sayCalculingExtractionAndDiseableWidgets();
    }
    this->editExtractionsWindow->selectFirstItem();
    this->editExtractionsWindow->show();
}


void MainWindow::loadSettings(){
    this->setVolume(this->settings.getVolume());
    this->continueButton->setChecked(this->settings.isContinuePlaying());
    this->continueAction->setChecked(this->settings.isContinuePlaying());
}

void MainWindow::showNormalOrMaximized(){
    //this only work under windows
    if(this->isMaximized){
        this->videoWidget->showNormal();
        this->isMaximized = false;
    }else{
        this->videoWidget->showFullScreen();
        this->isMaximized = true;
    }
}

void MainWindow::dragEnterEvent(QDragEnterEvent *event){
    if (event->mimeData()->hasText()){
        event->acceptProposedAction();
    }
}

void MainWindow::dropEvent(QDropEvent *event){
    QString fileName(event->mimeData()->urls().first().path());
    if(fileName.endsWith(".srt")){
        std::cout << "str file enter :" << fileName.toStdString() << std::endl;
        this->addSubtitle(fileName, 0);
    }else{
        //TODO it's probably a video but we should check that
        this->openVideo(fileName);
    }
}

void MainWindow::addSubtitle(QString strFileName, int idSubtitleTrack){
    QFont font("Liberation Serif");
    font.setWeight( QFont::Bold );
    font.setStyle( QFont::StyleItalic );
    font.setPointSize(30);
    QColor color(Qt::yellow); //TODO take from options
    this->videoManager->setSubtitleTrack(idSubtitleTrack, strFileName, font, color, 80);
}


